import SparkMD5 from 'spark-md5';

// src/utils/getHash.ts
export interface HashProgressCallback {
  (percent: number): void;
}

export function getHash(
  file: File,
  onProgress?: HashProgressCallback
): Promise<string> {
  const chunkSize = 5 * 1024 * 1024; // 5MB
  const workerCount = Math.max(navigator.hardwareConcurrency || 4, 2);
  const totalChunks = Math.ceil(file.size / chunkSize);
  return new Promise((resolve, reject) => {
    if (totalChunks === 0) {
      resolve(SparkMD5.hash('')); // 空文件
      return;
    }
    const workers: Worker[] = [];
    const spark = new SparkMD5.ArrayBuffer();

    let completed = 0;
    let dispatched = 0;
    let hasError = false;

    // 缓存乱序到达的 buffer，确保 append 顺序正确
    const bufferCache: (ArrayBuffer | null)[] = new Array(totalChunks).fill(
      null
    );
    let nextIndexToProcess = 0;

    const cleanupAndResolve = (hash: string) => {
      workers.forEach(w => w.terminate());
      resolve(hash);
    };

    const cleanupAndReject = (err: ErrorEvent) => {
      workers.forEach(w => w.terminate());
      reject(err);
    };

    // 处理连续可用的分片
    const processReadyBuffers = () => {
      while (
        nextIndexToProcess < totalChunks &&
        bufferCache[nextIndexToProcess] !== null
      ) {
        const buffer = bufferCache[nextIndexToProcess]!;
        spark.append(buffer);
        bufferCache[nextIndexToProcess] = null; // 释放内存

        completed++;

        onProgress?.((completed / totalChunks) * 100);

        nextIndexToProcess++;

        if (completed === totalChunks) {
          return cleanupAndResolve(spark.end());
        }
      }
    };

    // 创建 Worker
    for (let i = 0; i < workerCount; i++) {
      const worker = new Worker(new URL('./hash.worker.ts', import.meta.url), {
        type: 'module',
      });

      worker.onmessage = e => {
        if (hasError) return;

        const { index, buffer, error } = e.data;
        if (error) {
          hasError = true;
          cleanupAndReject(new ErrorEvent(`Chunk ${index}: ${error}`));
          return;
        }

        bufferCache[index] = buffer;
        processReadyBuffers();
      };

      worker.onerror = err => {
        hasError = true;
        cleanupAndReject(err);
      };

      workers.push(worker);
    }

    // 分发一个分片任务
    const dispatchChunk = (worker: Worker, index: number) => {
      const start = index * chunkSize;
      const end = Math.min(start + chunkSize, file.size);
      const slice = file.slice(start, end);

      worker.postMessage({ index, chunk: slice }); // chunk 可结构化克隆
    };

    // 初始分发
    for (let i = 0; i < workerCount && dispatched < totalChunks; i++) {
      dispatchChunk(workers[i], dispatched++);
    }

    // 流水线：Worker 空闲就分配新任务
    workers.forEach(worker => {
      const originalOnMessage = worker.onmessage;
      worker.onmessage = e => {
        originalOnMessage?.call(worker, e);
        if (!hasError && dispatched < totalChunks) {
          dispatchChunk(worker, dispatched++);
        }
      };
    });
  });
}
